/*
 * Copyright (c) 2004-2005, Volatile-Engine All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * Redistributions of source code must retain the above copyright notice, this
 * list of conditions and the following disclaimer.
 *
 * Redistributions in binary form must reproduce the above copyright notice,
 * this list of conditions and the following disclaimer in the documentation
 * and/or other materials provided with the distribution.
 *
 * Neither the name of the Volatile-Engine nor the
 * names of its contributors may be used to endorse or promote products derived
 * from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */
package com.volatileengine.datatypes;

import java.nio.Buffer;
import java.nio.ByteBuffer;

import javax.vecmath.Color4f;
import javax.vecmath.Quat4f;
import javax.vecmath.Tuple2f;
import javax.vecmath.Tuple3f;

/**
 * The VolatileEngine basic array type. This represents a list of 'chunks' of
 * data. Each chunk contains a number of data items equal to the chunk size of
 * this array.
 * 
 * @author ChaosDeathFish
 * @param <T>
 *             the type of the buffer backing this Array.
 */
public abstract class AbstractArray<T extends Buffer> {
	/**
	 * @return the Buffer object backing this Array.
	 */
	public abstract T getBuffer();

	/**
	 * @return the DataType of the data in this Array.
	 */
	public abstract DataType getType();

	/**
	 * @return the chunk size of this Array (i.e. the number of items in a
	 *         chunk)
	 */
	public abstract int getChunkSize();

	/**
	 * Creates an underlying buffer for this Array, if it does not already
	 * exist.
	 */
	public abstract void createBuffer();

	/**
	 * Deletes the underlying buffer for this Array, if it exists.
	 */
	public abstract void clearBuffer();

	/**
	 * Gets the position of the start of the specified chunk in the underlying
	 * buffer.
	 * 
	 * @param index
	 *             the chunk index to return.
	 * @return the position of the start of the specified chunk.
	 */
	public abstract int getBufferIndex(int index);

	/**
	 * @return the stride of this array, i.e. the number of elements in the
	 *         underlying buffer between the start of successive chunks. For
	 *         base arrays this will be the same as the chunk size, but will be
	 *         different for elements in interleaved arrays.
	 */
	public abstract int getStride();

	/**
	 * @return the position in the underlying buffer of the first chunk.
	 */
	public abstract int getOffset();

	/**
	 * @return the number of chunks that this Array stores.
	 */
	public abstract int getLength();

	/**
	 * @param length
	 *             the new length for this Array.
	 */
	public abstract void setLength(int length);

	/**
	 * @return the parent of this Array. If this Array is an element array,
	 *         this will return its parent, otherwise null.
	 */
	public AbstractArray<T> getParentArray() {
		return null;
	}

	/**
	 * @return the number of children this Array has. For non-interleaved
	 *         Arrays, this will always return 0.
	 */
	public int getChildCount() {
		return 0;
	}

	/**
	 * Gets the child Array at the specified index.
	 * 
	 * @param index
	 *             the index of the child to return.
	 * @return the child Array at the specified index.
	 * @throws IndexOutOfBoundsException
	 *              if the array index is out of bounds.
	 */
	public ArrayElement<T> getChildAt(int index) {
		throw new IndexOutOfBoundsException();
	}

	/**
	 * Gets two items of data from this Array into a Tuple2f.<br>
	 * NOTE: this method is not bounds-checked, for speed.
	 * 
	 * @param index
	 *             the chunk index to return data from.
	 * @param offset
	 *             the offset from the chunk start.
	 * @param target
	 *             the Tuple2f to store the data into.
	 * @return the target parameter, for chaining.
	 */
	public abstract Tuple2f getTuple2f(int index, int offset, Tuple2f target);

	/**
	 * Gets three items of data from this Array into a Tuple3f.<br>
	 * NOTE: this method is not bounds-checked, for speed.
	 * 
	 * @param index
	 *             the chunk index to return data from.
	 * @param offset
	 *             the offset from the chunk start.
	 * @param target
	 *             the Tuple3f to store the data into.
	 * @return the target parameter, for chaining.
	 */
	public abstract Tuple3f getTuple3f(int index, int offset, Tuple3f target);

	/**
	 * Gets four items of data from this Array into a Color4f.<br>
	 * NOTE: this method is not bounds-checked, for speed.
	 * 
	 * @param index
	 *             the chunk index to return data from.
	 * @param offset
	 *             the offset from the chunk start.
	 * @param target
	 *             the Color4f to store the data into.
	 * @return the target parameter, for chaining.
	 */
	public abstract Color4f getColor4f(int index, int offset, Color4f target);

	/**
	 * Gets four items of data from this Array into a Quaternion.<br>
	 * NOTE: this method is not bounds-checked, for speed.
	 * 
	 * @param index
	 *             the chunk index to return data from.
	 * @param offset
	 *             the offset from the chunk start.
	 * @param target
	 *             the Quaternion to store the data into.
	 * @return the target parameter, for chaining.
	 */
	public abstract Quat4f getQuat4f(int index, int offset, Quat4f target);

	/**
	 * Sets two items of data in this Array from a Tuple2f.<br>
	 * NOTE: this method is not bounds-checked, for speed.
	 * 
	 * @param index
	 *             the chunk index to set data to.
	 * @param offset
	 *             the offset from the chunk start.
	 * @param source
	 *             the Tuple2f to set the data from.
	 */
	public abstract void setTuple2f(int index, int offset, Tuple2f source);

	/**
	 * Sets three items of data in this Array from a Tuple3f.<br>
	 * NOTE: this method is not bounds-checked, for speed.
	 * 
	 * @param index
	 *             the chunk index to set data to.
	 * @param offset
	 *             the offset from the chunk start.
	 * @param source
	 *             the Tuple3f to set the data from.
	 */
	public abstract void setTuple3f(int index, int offset, Tuple3f source);

	/**
	 * Sets four items of data in this Array from a Color4f.<br>
	 * NOTE: this method is not bounds-checked, for speed.
	 * 
	 * @param index
	 *             the chunk index to set data to.
	 * @param offset
	 *             the offset from the chunk start.
	 * @param source
	 *             the Color4f to set the data from.
	 */
	public abstract void setColor4f(int index, int offset, Color4f source);

	/**
	 * Sets four items of data in this Array from a Quaternion.<br>
	 * NOTE: this method is not bounds-checked, for speed.
	 * 
	 * @param index
	 *             the chunk index to set data to.
	 * @param offset
	 *             the offset from the chunk start.
	 * @param source
	 *             the Quaternion to set the data from.
	 */
	public abstract void setQuat4f(int index, int offset, Quat4f source);

	/**
	 * Gets an item of data in this Array as a float.
	 * 
	 * @param index
	 *             the chunk index to get data from.
	 * @param offset
	 *             the offset from the chunk start.
	 * @return the item of data at the specified location, as a float.
	 */
	public abstract float getFloat(int index, int offset);

	/**
	 * Gets an item of data in this Array as an int.
	 * 
	 * @param index
	 *             the chunk index to get data from.
	 * @param offset
	 *             the offset from the chunk start.
	 * @return the item of data at the specified location, as an int.
	 */
	public abstract int getInt(int index, int offset);

	/**
	 * Gets an item of data in this Array as a byte.
	 * 
	 * @param index
	 *             the chunk index to get data from.
	 * @param offset
	 *             the offset from the chunk start.
	 * @return the item of data at the specified location, as a byte.
	 */
	public abstract byte getByte(int index, int offset);

	/**
	 * Sets an item of data in this Array to a float value.
	 * 
	 * @param index
	 *             the chunk index to set data to.
	 * @param offset
	 *             the offset from the chunk start.
	 * @param value
	 *             the float to set the specified location to.
	 */
	public abstract void setFloat(int index, int offset, float value);

	/**
	 * Sets an item of data in this Array to an int value.
	 * 
	 * @param index
	 *             the chunk index to set data to.
	 * @param offset
	 *             the offset from the chunk start.
	 * @param value
	 *             the int to set the specified location to.
	 */
	public abstract void setInt(int index, int offset, int value);

	/**
	 * Sets an item of data in this Array to a byte value.
	 * 
	 * @param index
	 *             the chunk index to set data to.
	 * @param offset
	 *             the offset from the chunk start.
	 * @param value
	 *             the byte to set the specified location to.
	 */
	public abstract void setByte(int index, int offset, byte value);

	/**
	 * Copies the data buffer of this array into the passed ByteBuffer.
	 * Optional for ElementArrays.
	 * 
	 * @param buffer
	 *             the ByteBuffer to copy into.
	 */
	public abstract void copyInto(ByteBuffer buffer);

	/**
	 * Populates the data buffer of this array from the passed ByteBuffer.
	 * Optional for ElementArrays.
	 * 
	 * @param buffer
	 *             the ByteBuffer to copy into.
	 */
	public abstract void copyFrom(ByteBuffer buffer);
}
